package dao

import (
	"fmt"
	"github.com/jmoiron/sqlx"
	"go-eth-tracker/models"
	"go.uber.org/zap"
)

type MssqlDao struct {
	DB         *sqlx.DB
	LogContext *zap.Logger
}

func (dao *MssqlDao) GetMerchant(merchantId string) *models.Merchant {
	sql := `SELECT * FROM BTCLikeMerchant WHERE Code=?`

	result := dao.DB.QueryRowx(sql, merchantId)
	if result == nil {
		dao.LogContext.Warn("没有对应的商户信息")
		return nil
	}

	var m models.Merchant
	err := result.StructScan(&m)
	if !dao.checkErr("GetAllMerchant Scan", err) {
		return &m
	}

	return nil
}

func (dao *MssqlDao) GetNextDerivationIndex(pubKey string) int {
	sql := `
DECLARE @nextIndex INT = 0;
IF EXISTS (SELECT 1 FROM BTCLikeDerivationStrategy WHERE Strategy=:strategy)
    UPDATE BTCLikeDerivationStrategy SET @nextIndex=CurrentIndex+1, CurrentIndex+=1, LastMdfTime=GETDATE() WHERE Strategy=:strategy;
ELSE
    INSERT INTO BTCLikeDerivationStrategy(Strategy, CurrentIndex, LastMdfTime)
    VALUES (:strategy, 0, GETDATE());
SELECT @nextIndex;
`

	result, err := dao.DB.NamedQuery(sql, map[string]interface{}{"strategy": pubKey})
	if err != nil {
		dao.checkErr("GetNextDerivationIndex Query", err)
	}

	var nextIndex int
	for result.Next() {
		err := result.Scan(&nextIndex)
		dao.checkErr("GetNextDerivationIndex Scan", err)
		break
	}

	return nextIndex
}

func (dao *MssqlDao) InsertAddress(address *models.BTCLikeAddress) int {
	sql := `
INSERT INTO dbo.BTCLikeAddress ( MerchantId, UserId, CryptoCode, PayAddress, ScriptPubKeyHash, DerivationStrategy, KeyPath,
                                  SubKeyPath, CreateTime )
VALUES  (:mchid, :uid, :code, :addr, :spkh, :derive, :kp, :skp, :ctime );
SELECT SCOPE_IDENTITY();`

	result, err := dao.DB.NamedQuery(sql, map[string]interface{}{
		"mchid": address.MerchantId,
		"uid": address.UserId,
		"code": address.CryptoCode,
		"addr": address.PayAddress,
		"spkh": address.ScriptPubKeyHash,
		"derive": address.DerivationStrategy,
		"kp": address.KeyPath,
		"skp": address.SubKeyPath,
		"ctime": address.CreateTime,
	})
	if err != nil {
		dao.checkErr("InsertAddress Exec", err)
	}

	var newAddressId int
	for result.Next() {
		err := result.Scan(&newAddressId)
		dao.checkErr("InsertAddress Scan", err)
		break
	}

	return newAddressId
}

func (dao *MssqlDao) checkErr(category string, err error) bool {
	if err != nil {
		dao.LogContext.Error(fmt.Sprintf("[ERROR]%s: %s", category, err.Error()))
		return true
	}
	return false
}
